#include "headers.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    defaultGrammarFile="grammar.xml";
    QGridLayout* layout=new QGridLayout();
    firstSymbolTXT=new QLineEdit();
    firstSymbolTXT->setReadOnly(true);
    firstSymbolTXT->setFocusPolicy(Qt::NoFocus);
    nonterminalsList=new QListWidget();    
    terminalsList=new QListWidget();
    rulesList=new QListWidget();
    actionTableWidget=new QTableWidget();
    gotoTableWidget=new QTableWidget();
    errorsList=new QListWidget();
    statusText=new QLabel();
    layout->addWidget(new QLabel(QObject::tr("First symbol:")), 0, 0, 1, 2, Qt::AlignRight);
    layout->addWidget(firstSymbolTXT, 0, 2, 1, 4);
    layout->addWidget(new QLabel(QObject::tr("Nonterminals:")), 1, 0, 1, 2);
    layout->addWidget(new QLabel(QObject::tr("Terminals:")), 1, 2, 1, 2);
    layout->addWidget(new QLabel(QObject::tr("Rules:")), 1, 4, 1, 2);
    layout->addWidget(nonterminalsList, 2, 0, 1, 2);
    layout->addWidget(terminalsList, 2, 2, 1, 2);
    layout->addWidget(rulesList, 2, 4, 1, 2);
    QGroupBox* box=new QGroupBox("Parser tables");
    QHBoxLayout* boxLayout=new QHBoxLayout();
    boxLayout->addWidget(actionTableWidget);
    boxLayout->addWidget(gotoTableWidget);
    box->setLayout(boxLayout);
    layout->addWidget(box, 4, 0, 1, 6);
    QDockWidget* dockWidget=new QDockWidget("Errors List:");
    dockWidget->setFeatures(QDockWidget::DockWidgetMovable);
    dockWidget->setWidget(errorsList);
    this->statusBar()->addWidget(statusText);
    this->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
    this->centralWidget()->setLayout(layout);
    gen=NULL;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::loadDefaultGrammar()
{
    if(!grammar.ReadFromXML(defaultGrammarFile))
    {
        QMessageBox* msg=new QMessageBox(QMessageBox::Information, QObject::tr("Load grammar"), QObject::tr("Failed to load default grammar. Do you want to specify new gramma file?"), QMessageBox::Cancel|QMessageBox::Ok, this);
        msg->exec();
        if(msg->result()==QMessageBox::Cancel)
            return;
        if(!loadGrammarFromFile())
            return;
    }
    PrintGrammar();
}

bool MainWindow::loadGrammarFromFile()
{
    QString fileName=QFileDialog::getOpenFileName(this, QObject::tr("Open file"), NULL, "XML file (*.xml)");
    if(fileName.isEmpty())
        return false;
    if(!grammar.ReadFromXML(fileName))
    {
        {
            QMessageBox* msg=new QMessageBox(QMessageBox::Information, QObject::tr("Load grammar"), QObject::tr("Failed to load grammar from file \"%1\". Do you want to specify other gramma file?").arg(fileName), QMessageBox::Cancel|QMessageBox::Ok, this);
            msg->exec();
            if(msg->result()==QMessageBox::Cancel)
                return false;
            return loadGrammarFromFile();
        }
    }
    actionTableWidget->clear();
    actionTableWidget->setRowCount(0);
    actionTableWidget->setColumnCount(0);
    gotoTableWidget->clear();
    gotoTableWidget->setRowCount(0);
    gotoTableWidget->setColumnCount(0);
    errorsList->clear();
    statusText->setText("");
    if(gen!=NULL)
    {
        delete gen;
        gen=NULL;
    }
    PrintGrammar();
    return true;
}

void MainWindow::PrintGrammar()
{
    nonterminalsList->clear();
    nonterminalsList->addItems(grammar.getNonterminals());
    terminalsList->clear();
    terminalsList->addItems(grammar.getTerminals());
    rulesList->clear();
    rulesList->addItems(grammar.getRules());
    firstSymbolTXT->setText(grammar.getFirstSymbol());
}

void MainWindow::generateParser()
{
    if(this->grammar.isEmpty())
    {
        QMessageBox::information(NULL, QObject::tr("Parser generator"),
                                 QObject::tr("Load grammar first"));
        return;
    }
    gen=new ParserGenerator(&grammar);

    actionTableWidget->clear();
    gotoTableWidget->clear();
    errorsList->clear();

    const ControlTable* actionTable=gen->GetActionTable();
    const ControlTable* gotoTable=gen->GetGotoTable();
    const QStringList* errors=gen->GetErrorsList();

    actionTableWidget->setRowCount(actionTable->GetHeight());
    actionTableWidget->setColumnCount(actionTable->GetWidth());
    actionTableWidget->setHorizontalHeaderLabels(actionTable->keys2());
    actionTableWidget->setVerticalHeaderLabels(actionTable->keys1string());

    gotoTableWidget->setRowCount(gotoTable->GetHeight());
    gotoTableWidget->setColumnCount(gotoTable->GetWidth());
    gotoTableWidget->setHorizontalHeaderLabels(gotoTable->keys2());
    gotoTableWidget->setVerticalHeaderLabels(gotoTable->keys1string());

    foreach(int key1, actionTable->keys1())
        foreach(QString key2, actionTable->keys2())
        {
            Cell* cell=new Cell();
            actionTable->GetValue(key1, key2, cell);
            actionTableWidget->setItem(actionTable->keys1().indexOf(key1), actionTable->keys2().indexOf(key2), new QTableWidgetItem(cell->ToString()));
        }
    foreach(int key1, gotoTable->keys1())
        foreach(QString key2, gotoTable->keys2())
        {
            Cell* cell=new Cell();
            gotoTable->GetValue(key1, key2, cell);
            gotoTableWidget->setItem(gotoTable->keys1().indexOf(key1), gotoTable->keys2().indexOf(key2), new QTableWidgetItem(cell->ToString()));
        }
    errorsList->addItems(*errors);
    statusText->clear();
    if(errors->count()!=0)
    {
        int conflicts=0;
        foreach(QString str, *errors)
            if(str.contains("Reduce-Reduce", Qt::CaseInsensitive))
                conflicts++;
        if(conflicts!=0)
            statusText->setText(QObject::tr("%1 Reduce-Reduce conflicts found").arg(conflicts));
        else
            statusText->setText("No Reduce-Reduce conflicts found");
    }
    else
        statusText->setText("Generate successfull");
}

void MainWindow::saveControlTables()
{
    if(grammar.isEmpty())
    {
        QMessageBox::information(NULL, QObject::tr("Parser generator"),
                                 QObject::tr("Load grammar first"));
        return;
    }
    if(gen==NULL)
    {
        QMessageBox::information(NULL, QObject::tr("Parser generator"),
                                 QObject::tr("Generate Control Tables next"));
        return;
    }
    QString fileName=QFileDialog::getSaveFileName(this, QObject::tr("Save file"), NULL, "XML file (*.xml)");
    if(fileName.isEmpty())
        return;
    if(!fileName.endsWith(".xml", Qt::CaseInsensitive))
        fileName.append(".xml");
    gen->SaveControlTables(fileName);
}
